package com.ibeeking.found.report.rest.config.redis;

import com.ibeeking.found.common.utils.ReflectUtils;
import com.ibeeking.found.report.rest.service.util.ReportUtils;
import com.ibeeking.found.report.service.common.annotation.HashKey;
import com.ibeeking.found.report.service.common.annotation.HashValue;
import com.ibeeking.found.report.service.common.bo.HashKeyValue;
import com.ibeeking.found.report.service.common.constant.enums.BaseOperationEnum;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 粗粒度的缓存服务，重构GaeaBaseService
 * @author WongBin
 * @date 2023/4/11
 */
public interface ReportCacheService {

    default String formatKey(String key,String[] replaceArray, Object entity) {
        return ReportUtils.formatKey(key,replaceArray,entity);
    }

    /***
     * 单行数据的缓存刷新
     * @param entity
     * @param opr
     */
    default <T> void refreshCacheFields(T entity, BaseOperationEnum opr){
        //更新缓存
        Field[] declaredFields = ReflectUtils.getAllFieldsArr(entity);
        Map<String, HashKeyValue> cacheMap = new HashMap<>();
        for(Field field : declaredFields) {
            field.setAccessible(true);
            Object value;

            if (field.isAnnotationPresent(HashKey.class)) {
                try {
                    value = field.get(entity);
                } catch (IllegalAccessException e) {
                    continue;
                }
                if (value == null) {
                    continue;
                }
                HashKey hashKey = field.getAnnotation(HashKey.class);
                String key = hashKey.key();
                //判断key是否存在
                if (cacheMap.containsKey(key)) {
                    HashKeyValue hashKeyValue = cacheMap.get(key);
                    hashKeyValue.setKey(String.valueOf(value));
                    hashKeyValue.setHashKey(hashKey);
                } else {
                    HashKeyValue hashKeyValue = new HashKeyValue();
                    hashKeyValue.setKey(String.valueOf(value));
                    hashKeyValue.setHashKey(hashKey);
                    cacheMap.put(key, hashKeyValue);
                }
            }

            if (field.isAnnotationPresent(HashValue.class)) {
                try {
                    value = field.get(entity);
                } catch (IllegalAccessException e) {
                    continue;
                }
                if (value == null) {
                    continue;
                }
                HashValue hashValue = field.getAnnotation(HashValue.class);
                String key = hashValue.key();
                //判断key是否存在
                if (cacheMap.containsKey(key)) {
                    HashKeyValue hashKeyValue = cacheMap.get(key);
                    hashKeyValue.setValue(String.valueOf(value));
                } else {
                    HashKeyValue hashKeyValue = new HashKeyValue();
                    hashKeyValue.setValue(String.valueOf(value));
                    cacheMap.put(key, hashKeyValue);
                }
            }
        }

        //缓存操作类
        CacheHelper cacheHelper = SpringBeanUtil.getBean(CacheHelper.class);
        if (BaseOperationEnum.DELETE == opr || BaseOperationEnum.DELETE_BATCH == opr) {
            //删除缓存
            cacheMap.entrySet().stream().filter(entry -> entry.getValue().nonNull()).forEach(entry -> {
                String k = formatKey(entry.getKey(),entry.getValue().getHashKey().replace(), entity);
                cacheHelper.hashDel(k, entry.getValue().getKey());
            });

        }
        if(BaseOperationEnum.INSERT == opr || BaseOperationEnum.UPDATE == opr){
            //刷新缓存，过滤掉HashKeyValue中，key为null或者value为null的情况
            cacheMap.entrySet().stream().filter(entry -> entry.getValue().nonNull()).forEach(entry -> {
                String k = formatKey(entry.getKey(),entry.getValue().getHashKey().replace(), entity);
                cacheHelper.hashSet(k, entry.getValue().getKey(), entry.getValue().getValue());
            });
        }
        if(BaseOperationEnum.DELETE_INSERT == opr){
            //刷新缓存，过滤掉HashKeyValue中，key为null或者value为null的情况
            cacheMap.entrySet().stream().filter(entry -> entry.getValue().nonNull()).forEach(entry -> {
                String k = formatKey(entry.getKey(),entry.getValue().getHashKey().replace(), entity);
                cacheHelper.hashDel(k, entry.getValue().getKey());
                cacheHelper.hashSet(k, entry.getValue().getKey(), entry.getValue().getValue());
            });
        }
        if(BaseOperationEnum.MERGE == opr){
            //刷新缓存，不过滤HashKeyValue中，key为null或者value为null的情况
            cacheMap.entrySet().stream().forEach(entry -> {
                String k = formatKey(entry.getKey(),entry.getValue().getHashKey().replace(), entity);
                //cacheHelper.hashDel(k, entry.getValue().getKey());
                cacheHelper.hashSet(k, entry.getValue().getKey(), entry.getValue().getValue());
            });
        }
    }

    /***
     * 批量数据同步缓存
     * @param entities
     * @param opr
     */
    @SuppressWarnings("unchecked")
    default <T> void refreshCacheFieldsBatch(List<T> entities, BaseOperationEnum opr){
        if(CollectionUtils.isEmpty(entities)){
            return;
        }
        T entity = entities.get(0);
        Field[] declaredFields = ReflectUtils.getAllFieldsArr(entity);
        //缓存操作类
        CacheHelper cacheHelper = SpringBeanUtil.getBean(CacheHelper.class);

        Map<String,Set<HashKeyValue>> cacheMap = new HashMap<>();
        for(T t : entities) {
            // 先遍历一遍 hash-key
            String namePrefix = "";
            String k = "";
            for (Field field : declaredFields) {
                field.setAccessible(true);
                Object value;
                if (field.isAnnotationPresent(HashKey.class)) {
                    try {
                        value = field.get(t);
                    } catch (IllegalAccessException ex) {
                        continue;
                    }
                    if (value == null) {
                        continue;
                    }
                    HashKey hashKey = field.getAnnotation(HashKey.class);
                    String key = hashKey.key();
                    namePrefix = formatKey(key, hashKey.replace(), t);
                    k = value+"";
                    if (cacheMap.containsKey(key)) {
                        Set<HashKeyValue> list = cacheMap.get(key);
                        HashKeyValue r = new HashKeyValue();
                        r.setKey(String.valueOf(value));
                        r.setHashKey(hashKey);
                        r.setName(namePrefix);
                        list.add(r);
                    } else {
                        HashKeyValue kv = new HashKeyValue();
                        kv.setKey(String.valueOf(value));
                        kv.setHashKey(hashKey);
                        kv.setName(namePrefix);
                        Set<HashKeyValue> list = new HashSet<>();
                        list.add(kv);
                        cacheMap.put(key, list);
                    }
                }
            }
            for (Field field : declaredFields) {
                field.setAccessible(true);
                Object value;
                if (field.isAnnotationPresent(HashValue.class)) {
                    try {
                        value = field.get(t);
                    } catch (IllegalAccessException e) {
                        continue;
                    }
                    if (value == null) {
                        continue;
                    }
                    HashValue hashValue = field.getAnnotation(HashValue.class);
                    String key = hashValue.key();

                    if (cacheMap.containsKey(key)) {
                        Set<HashKeyValue> list = cacheMap.get(key);
                        final String k1 = k;
                        final String ns = namePrefix;
                        list.stream().filter(f->f.getKey().equals(k1) && f.getName().equals(ns))
                                .findFirst().get().setValue(String.valueOf(value));
                    }
                }
            }
        }

        if (BaseOperationEnum.DELETE == opr || BaseOperationEnum.DELETE_BATCH == opr) {
            cacheMap.entrySet().stream().filter(entry -> !CollectionUtils.isEmpty(entry.getValue())).forEach(entry -> {
                Map<String,List<HashKeyValue>> map = entry.getValue().stream().collect(Collectors.groupingBy(t->t.getName()));
                map.entrySet().forEach(kv->{
                    cacheHelper.hashBatchDel(kv.getKey(),kv.getValue().stream().map(HashKeyValue::getKey).collect(Collectors.toSet()));
                });
            });
        }
        if(BaseOperationEnum.INSERT == opr || BaseOperationEnum.UPDATE == opr){
            cacheMap.entrySet().stream().filter(entry -> !CollectionUtils.isEmpty(entry.getValue())).forEach(entry -> {
                Map<String,List<HashKeyValue>> map = entry.getValue().stream().collect(Collectors.groupingBy(t->t.getName()));
                map.entrySet().forEach(kv->{
                    cacheHelper.hashSet(kv.getKey(),kv.getValue().stream()
                            .collect(Collectors.toMap(HashKeyValue::getKey,HashKeyValue::getValue,(v1,v2)->v2)));
                });
            });
        }
        if(BaseOperationEnum.DELETE_INSERT == opr){
            cacheMap.entrySet().stream().filter(entry -> !CollectionUtils.isEmpty(entry.getValue())).forEach(entry -> {
                Map<String,List<HashKeyValue>> map = entry.getValue().stream().collect(Collectors.groupingBy(t->t.getName()));
                map.entrySet().forEach(kv->{
                    cacheHelper.hashBatchDel(kv.getKey(),kv.getValue().stream().map(HashKeyValue::getKey).collect(Collectors.toSet()));
                    cacheHelper.hashSet(kv.getKey(),kv.getValue().stream()
                            .collect(Collectors.toMap(t->t.getKey(),t->t.getValue(),(v1,v2)->v2)));
                });
            });
        }
        if(BaseOperationEnum.MERGE == opr){
            cacheMap.entrySet().stream()/*.filter(entry -> !CollectionUtils.isEmpty(entry.getValue()))*/.forEach(entry -> {
                Map<String,List<HashKeyValue>> map = entry.getValue().stream().collect(Collectors.groupingBy(t->t.getName()));
                map.entrySet().forEach(kv->{
                    cacheHelper.hashSet(kv.getKey(),kv.getValue().stream()
                        .filter(e->!StringUtils.isEmpty(e.getKey()))
                        .collect(Collectors.toMap(t->t.getKey(),
                                t->Optional.ofNullable(t.getValue()).orElse(""),(v1,v2)->v2)));
                });
            });
        }
    }
}
